package top.tsyz.util;

import lombok.Data;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * MySQL代码生成器工具类
 * 根据数据库表结构生成Java POJO类
 */
public class MySQLCodeGenerator {
    /**
     * 使用示例
     *
     * @param args 命令行参数
     */
    public static void main(String[] args) {
        try {
            // 示例用法
            MySQLCodeGenerator generator = new MySQLCodeGenerator(
                    "jdbc:mysql://127.0.0.1:3306/myapp_db?useUnicode=true&characterEncoding=utf8",
                    "root",
                    "1234",
                    "top.tsyz",
                    "D:\\Code\\IdeaProjects\\learning_records\\springboot_demo"
            );

            // 定义要生成的表名列表
            List<String> tableNames = new ArrayList<>();
            tableNames.add("admin_roles");
            tableNames.add("admins");
            tableNames.add("brands");
            tableNames.add("categories");
            tableNames.add("coupons");
            tableNames.add("favorites");
            tableNames.add("operation_logs");
            tableNames.add("order_items");
            tableNames.add("orders");
            tableNames.add("payments");
            tableNames.add("product_reviews");
            tableNames.add("product_skus");
            tableNames.add("products");
            tableNames.add("roles");
            tableNames.add("shipments");
            tableNames.add("shopping_carts");
            tableNames.add("system_configs");
            tableNames.add("user_addresses");
            tableNames.add("user_coupons");
            tableNames.add("users");

            // 方式1: 生成指定的单个表的实体类
            // generator.generateAndSavePOJO("users");
            // System.out.println("实体类已生成并保存到指定目录");

            // 方式2: 生成多个指定的表的实体类
            //generator.generateAndSavePOJOs(tableNames);

            // 方式3: 生成所有类型的实体类（VO, BO, PO, DO, DTO, ENTITY）
            //generator.generateAllTypePOJOs(tableNames);

            // 方式4: 生成特定类型的实体类
            //generator.generateAndSavePOJOs(tableNames, EntityType.DTO);

            // 方式5: 生成所有相关代码（实体类、Mapper、Service、ServiceImpl、Controller、XML）
            //generator.generateAll(tableNames.get(0)); // 生成第一个表的所有代码

            // 方式6: 批量生成所有表的所有相关代码
            //generator.generateAll(tableNames);

            // 方式7: 生成数据库中所有表的所有相关代码
            generator.generateAllCodes();

        } catch (SQLException | IOException e) {
            e.printStackTrace();
        }
    }

    private final String url;
    private final String username;
    private final String password;
    private final String packageName;
    private final String projectPath;

    public MySQLCodeGenerator(String url, String username, String password, String packageName, String projectPath) {
        this.url = url;
        this.username = username;
        this.password = password;
        this.packageName = packageName;
        this.projectPath = projectPath;
    }

    /**
     * 将下划线命名转换为驼峰命名
     *
     * @param underscore            下划线命名
     * @param capitalizeFirstLetter 是否首字母大写
     * @return 驼峰命名
     */
    private static String toCamelCase(String underscore, boolean capitalizeFirstLetter) {
        if (underscore == null || underscore.isEmpty()) {
            return underscore;
        }

        StringBuilder result = new StringBuilder();
        boolean capitalizeNext = capitalizeFirstLetter;

        for (char c : underscore.toCharArray()) {
            if (c == '_') {
                capitalizeNext = true;
            } else {
                if (capitalizeNext) {
                    result.append(Character.toUpperCase(c));
                    capitalizeNext = false;
                } else {
                    result.append(Character.toLowerCase(c));
                }
            }
        }

        return result.toString();
    }



    /**
     * 根据表名生成POJO类
     *
     * @param tableName  表名
     * @param entityType 实体类类型
     * @return POJO类的Java代码
     * @throws SQLException 数据库访问异常
     */
    public String generatePOJO(String tableName, EntityType entityType) throws SQLException {
        Connection connection = DriverManager.getConnection(url, username, password);

        try {
            // 获取表的元数据
            DatabaseMetaData metaData = connection.getMetaData();
            String className = toEntityName(tableName) + getSuffixByType(entityType);

            // 构建类定义
            StringBuilder classBuilder = new StringBuilder();
            classBuilder.append("package ").append(packageName).append(".").append(entityType.getPackageName()).append(";\n\n");

            // 添加导入语句
            classBuilder.append("import io.swagger.annotations.ApiModel;\n");
            classBuilder.append("import io.swagger.annotations.ApiModelProperty;\n");
            classBuilder.append("import lombok.Data;\n");
            classBuilder.append("import lombok.NoArgsConstructor;\n");
            classBuilder.append("import lombok.AllArgsConstructor;\n");
            classBuilder.append("import javax.validation.constraints.*;\n");
            classBuilder.append("import java.util.Date;\n");
            classBuilder.append("import java.math.BigDecimal;\n\n");

            // 添加类注解
            classBuilder.append("@Data\n");
            classBuilder.append("@NoArgsConstructor\n");
            classBuilder.append("@AllArgsConstructor\n");
            classBuilder.append("@ApiModel(description = \"").append(className).append(" ").append(getDescriptionByType(entityType)).append("\")\n");
            classBuilder.append("public class ").append(className).append(" {\n\n");

            // 获取表的列信息
            List<Column> columns = getColumns(connection, tableName);

            // 生成私有字段
            for (Column column : columns) {
                // 添加Swagger注解
                classBuilder.append("    @ApiModelProperty(value = \"")
                        .append(column.getComment() != null && !column.getComment().isEmpty() ? column.getComment() : column.getPropertyName())
                        .append("\")\n");

                // 添加验证注解
                if (!column.isNullable() && "String".equals(column.getJavaType())) {
                    classBuilder.append("    @NotBlank(message = \"")
                            .append(column.getComment() != null && !column.getComment().isEmpty() ? column.getComment() : column.getPropertyName())
                            .append("不能为空\")\n");
                }

                // 添加长度验证注解
                if ("String".equals(column.getJavaType()) && column.getCharacterMaximumLength() != null) {
                    classBuilder.append("    @Size(max = ").append(column.getCharacterMaximumLength())
                            .append(", message = \"")
                            .append(column.getComment() != null && !column.getComment().isEmpty() ? column.getComment() : column.getPropertyName())
                            .append("长度不能超过").append(column.getCharacterMaximumLength()).append("个字符\")\n");
                }

                // 特殊字段验证注解
                if ("String".equals(column.getJavaType()) && column.getPropertyName().toLowerCase().contains("email")) {
                    classBuilder.append("    @Email(message = \"邮箱格式不正确\")\n");
                }

                classBuilder.append("    private ").append(column.getJavaType()).append(" ").append(column.getPropertyName()).append(";\n\n");
            }

            classBuilder.append("}\n");

            return classBuilder.toString();
        } finally {
            connection.close();
        }
    }

    /**
     * 根据表名生成默认的实体类（ENTITY类型）
     *
     * @param tableName 表名
     * @return POJO类的Java代码
     * @throws SQLException 数据库访问异常
     */
    public String generatePOJO(String tableName) throws SQLException {
        return generatePOJO(tableName, EntityType.ENTITY);
    }

    /**
     * 生成Mapper接口代码
     *
     * @param tableName 表名
     * @return Mapper接口代码
     * @throws SQLException 数据库访问异常
     */
    public String generateMapper(String tableName) throws SQLException {
        String className = toEntityName(tableName);
        String mapperName = className + "Mapper";

        StringBuilder mapperBuilder = new StringBuilder();
        mapperBuilder.append("package ").append(packageName).append(".mapper;\n\n");

        mapperBuilder.append("import ").append(packageName).append(".entity.").append(className).append(";\n");
        mapperBuilder.append("import com.baomidou.mybatisplus.core.mapper.BaseMapper;\n");
        mapperBuilder.append("import org.apache.ibatis.annotations.Mapper;\n\n");

        mapperBuilder.append("/**\n");
        mapperBuilder.append(" * ").append(className).append("Mapper接口\n");
        mapperBuilder.append(" */\n");
        mapperBuilder.append("@Mapper\n");
        mapperBuilder.append("public interface ").append(mapperName).append(" extends BaseMapper<").append(className).append("> {\n\n");
        mapperBuilder.append("}\n");

        return mapperBuilder.toString();
    }

    /**
     * 生成Service接口代码
     *
     * @param tableName 表名
     * @return Service接口代码
     * @throws SQLException 数据库访问异常
     */
    public String generateService(String tableName) throws SQLException {
        String className = toEntityName(tableName);
        String serviceName = "I" + className + "Service";

        StringBuilder serviceBuilder = new StringBuilder();
        serviceBuilder.append("package ").append(packageName).append(".service;\n\n");

        serviceBuilder.append("import ").append(packageName).append(".entity.").append(className).append(";\n");
        serviceBuilder.append("import com.baomidou.mybatisplus.extension.service.IService;\n\n");

        serviceBuilder.append("/**\n");
        serviceBuilder.append(" * ").append(className).append("Service接口\n");
        serviceBuilder.append(" */\n");
        serviceBuilder.append("public interface ").append(serviceName).append(" extends IService<").append(className).append("> {\n\n");
        serviceBuilder.append("}\n");

        return serviceBuilder.toString();
    }

    /**
     * 生成ServiceImpl实现类代码
     *
     * @param tableName 表名
     * @return ServiceImpl实现类代码
     * @throws SQLException 数据库访问异常
     */
    public String generateServiceImpl(String tableName) throws SQLException {
        String className = toEntityName(tableName);
        String serviceImplName = className + "ServiceImpl";
        String serviceName = "I" + className + "Service";

        StringBuilder serviceImplBuilder = new StringBuilder();
        serviceImplBuilder.append("package ").append(packageName).append(".service.impl;\n\n");

        serviceImplBuilder.append("import ").append(packageName).append(".entity.").append(className).append(";\n");
        serviceImplBuilder.append("import ").append(packageName).append(".mapper.").append(className).append("Mapper;\n");
        serviceImplBuilder.append("import ").append(packageName).append(".service.").append(serviceName).append(";\n");
        serviceImplBuilder.append("import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;\n");
        serviceImplBuilder.append("import org.springframework.stereotype.Service;\n\n");

        serviceImplBuilder.append("/**\n");
        serviceImplBuilder.append(" * ").append(className).append("ServiceImpl实现类\n");
        serviceImplBuilder.append(" */\n");
        serviceImplBuilder.append("@Service\n");
        serviceImplBuilder.append("public class ").append(serviceImplName).append(" extends ServiceImpl<").append(className).append("Mapper, ").append(className).append("> implements ").append(serviceName).append(" {\n\n");
        serviceImplBuilder.append("}\n");

        return serviceImplBuilder.toString();
    }

    /**
     * 生成Controller代码
     *
     * @param tableName 表名
     * @return Controller代码
     * @throws SQLException 数据库访问异常
     */
    public String generateController(String tableName) throws SQLException {
        String className = toEntityName(tableName);
        String controllerName = className + "Controller";
        String serviceName = "I" + className + "Service";

        StringBuilder controllerBuilder = new StringBuilder();
        controllerBuilder.append("package ").append(packageName).append(".controller;\n\n");

        controllerBuilder.append("import ").append(packageName).append(".entity.").append(className).append(";\n");
        controllerBuilder.append("import ").append(packageName).append(".service.").append(serviceName).append(";\n");
        controllerBuilder.append("import io.swagger.annotations.Api;\n");
        controllerBuilder.append("import io.swagger.annotations.ApiOperation;\n");
        controllerBuilder.append("import org.springframework.beans.factory.annotation.Autowired;\n");
        controllerBuilder.append("import org.springframework.web.bind.annotation.*;\n");
        controllerBuilder.append("import java.util.List;\n\n");

        controllerBuilder.append("/**\n");
        controllerBuilder.append(" * ").append(className).append("Controller控制器\n");
        controllerBuilder.append(" */\n");
        controllerBuilder.append("@RestController\n");
        controllerBuilder.append("@RequestMapping(\"/api/").append(toCamelCase(tableName, false)).append("\")\n");
        controllerBuilder.append("@Api(tags = \"").append(className).append("管理接口\")\n");
        controllerBuilder.append("public class ").append(controllerName).append(" {\n\n");

        controllerBuilder.append("    @Autowired\n");
        controllerBuilder.append("    private ").append(serviceName).append(" ").append(toCamelCase(serviceName, false)).append(";\n\n");

        controllerBuilder.append("    @GetMapping(\"/list\")\n");
        controllerBuilder.append("    @ApiOperation(\"获取所有").append(className).append("\")\n");
        controllerBuilder.append("    public List<").append(className).append("> list() {\n");
        controllerBuilder.append("        return ").append(toCamelCase(serviceName, false)).append(".list();\n");
        controllerBuilder.append("    }\n\n");

        controllerBuilder.append("    @GetMapping(\"/{id}\")\n");
        controllerBuilder.append("    @ApiOperation(\"根据ID获取").append(className).append("\")\n");
        controllerBuilder.append("    public ").append(className).append(" getById(@PathVariable Long id) {\n");
        controllerBuilder.append("        return ").append(toCamelCase(serviceName, false)).append(".getById(id);\n");
        controllerBuilder.append("    }\n\n");

        controllerBuilder.append("    @PostMapping\n");
        controllerBuilder.append("    @ApiOperation(\"新增").append(className).append("\")\n");
        controllerBuilder.append("    public boolean save(@RequestBody ").append(className).append(" ").append(toCamelCase(className, false)).append(") {\n");
        controllerBuilder.append("        return ").append(toCamelCase(serviceName, false)).append(".save(").append(toCamelCase(className, false)).append(");\n");
        controllerBuilder.append("    }\n\n");

        controllerBuilder.append("    @PutMapping\n");
        controllerBuilder.append("    @ApiOperation(\"更新").append(className).append("\")\n");
        controllerBuilder.append("    public boolean update(@RequestBody ").append(className).append(" ").append(toCamelCase(className, false)).append(") {\n");
        controllerBuilder.append("        return ").append(toCamelCase(serviceName, false)).append(".updateById(").append(toCamelCase(className, false)).append(");\n");
        controllerBuilder.append("    }\n\n");

        controllerBuilder.append("    @DeleteMapping(\"/{id}\")\n");
        controllerBuilder.append("    @ApiOperation(\"删除").append(className).append("\")\n");
        controllerBuilder.append("    public boolean delete(@PathVariable Long id) {\n");
        controllerBuilder.append("        return ").append(toCamelCase(serviceName, false)).append(".removeById(id);\n");
        controllerBuilder.append("    }\n");
        controllerBuilder.append("}\n");

        return controllerBuilder.toString();
    }

    /**
     * 生成XML映射文件代码
     *
     * @param tableName 表名
     * @return XML映射文件代码
     * @throws SQLException 数据库访问异常
     */
    public String generateXmlMapper(String tableName) throws SQLException {
        String className = toEntityName(tableName);

        StringBuilder xmlBuilder = new StringBuilder();
        xmlBuilder.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
        xmlBuilder.append("<!DOCTYPE mapper PUBLIC \"-//mybatis.org//DTD Mapper 3.0//EN\" \"http://mybatis.org/dtd/mybatis-3-mapper.dtd\">\n");
        xmlBuilder.append("<mapper namespace=\"").append(packageName).append(".mapper.").append(className).append("Mapper\">\n\n");

        xmlBuilder.append("    <!-- 通用查询映射结果 -->\n");
        xmlBuilder.append("    <resultMap id=\"BaseResultMap\" type=\"").append(packageName).append(".entity.").append(className).append("\">\n");

        // 获取表的列信息
        Connection connection = DriverManager.getConnection(url, username, password);
        try {
            List<Column> columns = getColumns(connection, tableName);
            for (Column column : columns) {
                xmlBuilder.append("        <result column=\"").append(column.getColumnName())
                        .append("\" property=\"").append(column.getPropertyName()).append("\" />\n");
            }
        } finally {
            connection.close();
        }

        xmlBuilder.append("    </resultMap>\n\n");

        xmlBuilder.append("    <!-- 通用查询结果列 -->\n");
        xmlBuilder.append("    <sql id=\"Base_Column_List\">\n");
        xmlBuilder.append("        ");

        // 获取表的列信息
        connection = DriverManager.getConnection(url, username, password);
        try {
            List<Column> columns = getColumns(connection, tableName);
            for (int i = 0; i < columns.size(); i++) {
                xmlBuilder.append(columns.get(i).getColumnName());
                if (i < columns.size() - 1) {
                    xmlBuilder.append(", ");
                }
            }
        } finally {
            connection.close();
        }

        xmlBuilder.append("\n    </sql>\n\n");
        xmlBuilder.append("</mapper>\n");

        return xmlBuilder.toString();
    }

    /**
     * 根据表名和实体类型生成POJO类并保存到文件
     *
     * @param tableName  表名
     * @param entityType 实体类类型
     * @throws SQLException 数据库访问异常
     * @throws IOException  文件写入异常
     */
    public void generateAndSavePOJO(String tableName, EntityType entityType) throws SQLException, IOException {
        String pojoCode = generatePOJO(tableName, entityType);
        String className = toEntityName(tableName) + getSuffixByType(entityType);

        // 构建文件路径
        String packagePath = packageName.replace(".", File.separator) + File.separator + entityType.getPackageName();
        String filePath = projectPath + File.separator + "src" + File.separator + "main" + File.separator +
                "java" + File.separator + packagePath + File.separator + className + ".java";

        // 创建目录（如果不存在）
        File file = new File(filePath);
        file.getParentFile().mkdirs();

        // 写入文件
        try (FileWriter writer = new FileWriter(file)) {
            writer.write(pojoCode);
        }
    }

    /**
     * 根据表名生成默认的实体类并保存到文件（ENTITY类型）
     *
     * @param tableName 表名
     * @throws SQLException 数据库访问异常
     * @throws IOException  文件写入异常
     */
    public void generateAndSavePOJO(String tableName) throws SQLException, IOException {
        generateAndSavePOJO(tableName, EntityType.ENTITY);
    }

    /**
     * 生成Mapper接口并保存到文件
     *
     * @param tableName 表名
     * @throws SQLException 数据库访问异常
     * @throws IOException  文件写入异常
     */
    public void generateAndSaveMapper(String tableName) throws SQLException, IOException {
        String mapperCode = generateMapper(tableName);
        String className = toEntityName(tableName);
        String mapperName = className + "Mapper";

        // 构建文件路径
        String packagePath = packageName.replace(".", File.separator) + File.separator + "mapper";
        String filePath = projectPath + File.separator + "src" + File.separator + "main" + File.separator +
                "java" + File.separator + packagePath + File.separator + mapperName + ".java";

        // 创建目录（如果不存在）
        File file = new File(filePath);
        file.getParentFile().mkdirs();

        // 写入文件
        try (FileWriter writer = new FileWriter(file)) {
            writer.write(mapperCode);
        }
        System.out.println("Mapper接口 " + mapperName + " 已生成并保存到指定目录");
    }

    /**
     * 生成Service接口并保存到文件
     *
     * @param tableName 表名
     * @throws SQLException 数据库访问异常
     * @throws IOException  文件写入异常
     */
    public void generateAndSaveService(String tableName) throws SQLException, IOException {
        String serviceCode = generateService(tableName);
        String className = toEntityName(tableName);
        String serviceName = "I" + className + "Service";

        // 构建文件路径
        String packagePath = packageName.replace(".", File.separator) + File.separator + "service";
        String filePath = projectPath + File.separator + "src" + File.separator + "main" + File.separator +
                "java" + File.separator + packagePath + File.separator + serviceName + ".java";

        // 创建目录（如果不存在）
        File file = new File(filePath);
        file.getParentFile().mkdirs();

        // 写入文件
        try (FileWriter writer = new FileWriter(file)) {
            writer.write(serviceCode);
        }
        System.out.println("Service接口 " + serviceName + " 已生成并保存到指定目录");
    }

    /**
     * 生成ServiceImpl实现类并保存到文件
     *
     * @param tableName 表名
     * @throws SQLException 数据库访问异常
     * @throws IOException  文件写入异常
     */
    public void generateAndSaveServiceImpl(String tableName) throws SQLException, IOException {
        String serviceImplCode = generateServiceImpl(tableName);
        String className = toEntityName(tableName);
        String serviceImplName = className + "ServiceImpl";

        // 构建文件路径
        String packagePath = packageName.replace(".", File.separator) + File.separator + "service" + File.separator + "impl";
        String filePath = projectPath + File.separator + "src" + File.separator + "main" + File.separator +
                "java" + File.separator + packagePath + File.separator + serviceImplName + ".java";

        // 创建目录（如果不存在）
        File file = new File(filePath);
        file.getParentFile().mkdirs();

        // 写入文件
        try (FileWriter writer = new FileWriter(file)) {
            writer.write(serviceImplCode);
        }
        System.out.println("ServiceImpl实现类 " + serviceImplName + " 已生成并保存到指定目录");
    }

    /**
     * 生成Controller并保存到文件
     *
     * @param tableName 表名
     * @throws SQLException 数据库访问异常
     * @throws IOException  文件写入异常
     */
    public void generateAndSaveController(String tableName) throws SQLException, IOException {
        String controllerCode = generateController(tableName);
        String className = toEntityName(tableName);
        String controllerName = className + "Controller";

        // 构建文件路径
        String packagePath = packageName.replace(".", File.separator) + File.separator + "controller";
        String filePath = projectPath + File.separator + "src" + File.separator + "main" + File.separator +
                "java" + File.separator + packagePath + File.separator + controllerName + ".java";

        // 创建目录（如果不存在）
        File file = new File(filePath);
        file.getParentFile().mkdirs();

        // 写入文件
        try (FileWriter writer = new FileWriter(file)) {
            writer.write(controllerCode);
        }
        System.out.println("Controller控制器 " + controllerName + " 已生成并保存到指定目录");
    }

    /**
     * 生成XML映射文件并保存到文件
     *
     * @param tableName 表名
     * @throws SQLException 数据库访问异常
     * @throws IOException  文件写入异常
     */
    public void generateAndSaveXmlMapper(String tableName) throws SQLException, IOException {
        String xmlCode = generateXmlMapper(tableName);
        String className = toEntityName(tableName);
        String xmlName = className + "Mapper";

        // 构建文件路径
        String filePath = projectPath + File.separator + "src" + File.separator + "main" + File.separator +
                "resources" + File.separator + "mapper" + File.separator + xmlName + ".xml";

        // 创建目录（如果不存在）
        File file = new File(filePath);
        file.getParentFile().mkdirs();

        // 写入文件
        try (FileWriter writer = new FileWriter(file)) {
            writer.write(xmlCode);
        }
        System.out.println("XML映射文件 " + xmlName + ".xml 已生成并保存到指定目录");
    }

    /**
     * 生成所有相关代码文件（实体类、Mapper、Service、ServiceImpl、Controller、XML）
     *
     * @param tableName 表名
     * @throws SQLException 数据库访问异常
     * @throws IOException  文件写入异常
     */
    public void generateAll(String tableName) throws SQLException, IOException {
        // 生成实体类
        generateAndSavePOJO(tableName);

        // 生成Mapper接口
        generateAndSaveMapper(tableName);

        // 生成Service接口
        generateAndSaveService(tableName);

        // 生成ServiceImpl实现类
        generateAndSaveServiceImpl(tableName);

        // 生成Controller
        generateAndSaveController(tableName);

        // 生成XML映射文件
        generateAndSaveXmlMapper(tableName);

        System.out.println("表 " + tableName + " 的所有相关代码已生成完毕");
    }

    /**
     * 批量生成多个表的POJO类并保存到文件
     *
     * @param tableNames 表名列表
     * @param entityType 实体类类型
     * @throws SQLException 数据库访问异常
     * @throws IOException  文件写入异常
     */
    public void generateAndSavePOJOs(List<String> tableNames, EntityType entityType) throws SQLException, IOException {
        for (String tableName : tableNames) {
            generateAndSavePOJO(tableName, entityType);
            System.out.println("实体类 " + toEntityName(tableName) + getSuffixByType(entityType) + " 已生成并保存到指定目录");
        }
    }

    /**
     * 批量生成多个表的默认实体类并保存到文件（ENTITY类型）
     *
     * @param tableNames 表名列表
     * @throws SQLException 数据库访问异常
     * @throws IOException  文件写入异常
     */
    public void generateAndSavePOJOs(List<String> tableNames) throws SQLException, IOException {
        generateAndSavePOJOs(tableNames, EntityType.ENTITY);
    }

    /**
     * 批量生成所有相关代码文件（实体类、Mapper、Service、ServiceImpl、Controller、XML）
     *
     * @param tableNames 表名列表
     * @throws SQLException 数据库访问异常
     * @throws IOException  文件写入异常
     */
    public void generateAll(List<String> tableNames) throws SQLException, IOException {
        for (String tableName : tableNames) {
            generateAll(tableName);
        }
        System.out.println("所有表的相关代码已生成完毕");
    }

    /**
     * 为所有表生成所有类型的实体类
     *
     * @param tableNames 表名列表
     * @throws SQLException 数据库访问异常
     * @throws IOException  文件写入异常
     */
    public void generateAllTypePOJOs(List<String> tableNames) throws SQLException, IOException {
        for (EntityType entityType : EntityType.values()) {
            generateAndSavePOJOs(tableNames, entityType);
        }
        System.out.println("所有类型的实体类已生成并保存到指定目录");
    }

    /**
     * 获取所有表名
     *
     * @return 表名列表
     * @throws SQLException 数据库访问异常
     */
    public List<String> getAllTableNames() throws SQLException {
        List<String> tableNames = new ArrayList<>();
        Connection connection = DriverManager.getConnection(url, username, password);

        try {
            DatabaseMetaData metaData = connection.getMetaData();
            ResultSet rs = metaData.getTables(null, null, "%", new String[]{"TABLE"});

            while (rs.next()) {
                tableNames.add(rs.getString("TABLE_NAME"));
            }
        } finally {
            connection.close();
        }

        return tableNames;
    }

    /**
     * 生成数据库中所有表的POJO类并保存到文件
     *
     * @param entityType 实体类类型
     * @throws SQLException 数据库访问异常
     * @throws IOException  文件写入异常
     */
    public void generateAllPOJOs(EntityType entityType) throws SQLException, IOException {
        List<String> tableNames = getAllTableNames();
        generateAndSavePOJOs(tableNames, entityType);
        System.out.println("所有" + getDescriptionByType(entityType) + "已生成并保存到指定目录");
    }

    /**
     * 生成数据库中所有表的默认实体类并保存到文件（ENTITY类型）
     *
     * @throws SQLException 数据库访问异常
     * @throws IOException  文件写入异常
     */
    public void generateAllPOJOs() throws SQLException, IOException {
        generateAllPOJOs(EntityType.ENTITY);
    }

    /**
     * 为数据库中所有表生成所有类型的实体类
     *
     * @throws SQLException 数据库访问异常
     * @throws IOException  文件写入异常
     */
    public void generateAllTypePOJOs() throws SQLException, IOException {
        List<String> tableNames = getAllTableNames();
        generateAllTypePOJOs(tableNames);
    }

    /**
     * 生成数据库中所有表的所有相关代码文件
     *
     * @throws SQLException 数据库访问异常
     * @throws IOException  文件写入异常
     */
    public void generateAllCodes() throws SQLException, IOException {
        List<String> tableNames = getAllTableNames();
        generateAll(tableNames);
    }

    /**
     * 根据实体类型获取后缀
     *
     * @param entityType 实体类型
     * @return 后缀
     */
    private String getSuffixByType(EntityType entityType) {
        switch (entityType) {
            case VO:
                return "VO";
            case BO:
                return "BO";
            case PO:
                return "PO";
            case DO:
                return "DO";
            case DTO:
                return "DTO";
            default:
                return ""; // ENTITY类型不添加后缀
        }
    }

    /**
     * 根据实体类型获取描述
     *
     * @param entityType 实体类型
     * @return 描述
     */
    private String getDescriptionByType(EntityType entityType) {
        switch (entityType) {
            case VO:
                return "视图对象";
            case BO:
                return "业务对象";
            case PO:
                return "持久化对象";
            case DO:
                return "数据对象";
            case DTO:
                return "数据传输对象";
            default:
                return "实体类";
        }
    }

    /**
     * 将表名转换为实体类名
     * 例如: admin_roles -> AdminRole, users -> User
     *
     * @param tableName 表名
     * @return 实体类名
     */
    private String toEntityName(String tableName) {
        // 移除末尾的s或es（复数形式）
        String singularName = tableName;
        if (tableName.endsWith("ies")) {
            // 以ies结尾的复数形式，如categories -> Category
            singularName = tableName.substring(0, tableName.length() - 3) + "y";
        } else if (tableName.endsWith("es")) {
            // 以es结尾的复数形式，如roles -> Role
            singularName = tableName.substring(0, tableName.length() - 2);
        } else if (tableName.endsWith("s") && tableName.length() > 1) {
            // 以s结尾的复数形式，如users -> User
            singularName = tableName.substring(0, tableName.length() - 1);
        }

        // 转换为驼峰命名
        return toCamelCase(singularName, true);
    }

    /**
     * 获取表的所有列信息
     *
     * @param connection 数据库连接
     * @param tableName  表名
     * @return 列信息列表
     * @throws SQLException 数据库访问异常
     */
    private List<Column> getColumns(Connection connection, String tableName) throws SQLException {
        List<Column> columns = new ArrayList<>();
        String query = "SELECT COLUMN_NAME, DATA_TYPE, IS_NULLABLE, COLUMN_COMMENT, CHARACTER_MAXIMUM_LENGTH " +
                "FROM INFORMATION_SCHEMA.COLUMNS " +
                "WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? " +
                "ORDER BY ORDINAL_POSITION";

        PreparedStatement stmt = connection.prepareStatement(query);
        stmt.setString(1, tableName);
        ResultSet rs = stmt.executeQuery();

        while (rs.next()) {
            Column column = new Column();
            column.setColumnName(rs.getString("COLUMN_NAME"));
            column.setDataType(rs.getString("DATA_TYPE"));
            column.setNullable("YES".equals(rs.getString("IS_NULLABLE")));
            column.setComment(rs.getString("COLUMN_COMMENT"));
            if (rs.getObject("CHARACTER_MAXIMUM_LENGTH") != null) {
                column.setCharacterMaximumLength(rs.getInt("CHARACTER_MAXIMUM_LENGTH"));
            }
            columns.add(column);
        }

        return columns;
    }

    // 定义生成的实体类类型
    public enum EntityType {
        ENTITY("entity"),
        VO("vo"),           // View Object
        BO("bo"),           // Business Object
        PO("po"),           // Persistent Object
        DO("do"),           // Data Object
        DTO("dto");         // Data Transfer Object

        private final String packageName;

        EntityType(String packageName) {
            this.packageName = packageName;
        }

        public String getPackageName() {
            return packageName;
        }
    }

    // 定义生成的代码类型
    public enum CodeType {
        ENTITY, MAPPER, SERVICE, SERVICE_IMPL, CONTROLLER, XML
    }

    /**
     * 表示数据库列的信息
     */
    @Data
    private static class Column {
        private String columnName;
        private String dataType;
        private boolean nullable;
        private String comment;
        private Integer characterMaximumLength;


        /**
         * 获取对应的Java类型
         *
         * @return Java类型
         */
        public String getJavaType() {
            switch (dataType.toLowerCase()) {
                case "int":
                case "integer":
                    return "Integer";
                case "bigint":
                    return "Long";
                case "tinyint":
                    return "Boolean";
                case "smallint":
                    return "Short";
                case "float":
                    return "Float";
                case "double":
                    return "Double";
                case "decimal":
                case "numeric":
                    return "BigDecimal";
                case "varchar":
                case "char":
                case "text":
                case "longtext":
                case "mediumtext":
                case "tinytext":
                    return "String";
                case "datetime":
                case "timestamp":
                    return "Date";
                case "date":
                    return "Date";
                case "time":
                    return "Date";
                default:
                    return "String";
            }
        }

        /**
         * 获取属性名（驼峰命名）
         *
         * @return 属性名
         */
        public String getPropertyName() {
            return toCamelCase(columnName, false);
        }

        public Integer getCharacterMaximumLength() {
            return characterMaximumLength;
        }

        public void setCharacterMaximumLength(Integer characterMaximumLength) {
            this.characterMaximumLength = characterMaximumLength;
        }
    }
}
